﻿using DataType;
using DataType.Actions;
using DataType.CustomEnumType;
using DataType.JudgeResults;
using DataType.MessageType;
using MapCalclator;
using OprsSimulator.OprAttributes;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OprsSimulator.Operators
{
    public class DroneOpr : IOperator, ICommonAttris, IMoveAttris, IReconnaissanceAttris, IStateAttris, IAttackAttris
    {
        //ICommonAttris
        private int obj_id;
        private string name;
        private Color color;
        private OprType type;
        private OprSubType sub_type;
        private int value;
        private int blood;
        private int max_blood;

        public int ObjID { get => obj_id; }
        public string Name { get => name; }

        public Color Color { get => color; }

        public OprType Type { get => type; }

        public OprSubType Subtype { get => sub_type; }

        public int Value { get => value; }

        public int Blood { get => blood; set => blood = value; }

        public int MaxBlood { get => max_blood; }
        //IMoveAttris
        private int basic_speed;
        private MoveStateType move_state;
        private int cur_hex;
        private float cur_pos;
        private int speed;
        private int move_to_stop_remain_time;
        private bool can_to_move;
        private bool flag_force_stop;
        private bool stop;
        private List<int> move_path;
        private int tire;
        private int tire_accumulate_time;
        private bool on_board;
        private int car;
        private int launcher;
        private int get_on_remain_time;
        private List<int> get_on_partner_id;
        private int get_off_remain_time;
        private List<int> get_off_partner_id;
        private int change_state_remain_time;
        private MoveStateType target_state;

        public int BasicSpeed { get => basic_speed; }

        public MoveStateType MoveState { get => move_state; set => move_state = value; }
        public int CurHex { get => cur_hex; set => cur_hex = value; }
        public float CurPos { get => cur_pos; set => cur_pos = value; }
        public int Speed { get => speed; set => speed = value; }
        public int MoveToStopRemainTime { get => move_to_stop_remain_time; set => move_to_stop_remain_time = value; }
        public bool CanToMove { get => can_to_move; set => can_to_move = value; }
        public bool FlagForceStop { get => flag_force_stop; set => flag_force_stop = value; }
        public bool Stop { get => stop; set => stop = value; }
        public List<int> MovePath { get => move_path; set => move_path = value; }
        public int Tire { get => tire; set => tire = value; }
        public int TireAccumulateTime { get => tire_accumulate_time; set => tire_accumulate_time = value; }
        public bool OnBoard { get => on_board; set => on_board = value; }
        public int Car { get => car; set => car = value; }
        public int Launcher { get => launcher; set => launcher = value; }
        public int GetOnRemainTime { get => get_on_remain_time; set => get_on_remain_time = value; }
        public List<int> GetOnPartnerId { get => get_on_partner_id; set => get_on_partner_id = value; }
        public int GetOffRemainTime { get => get_off_remain_time; set => get_off_remain_time = value; }
        public List<int> GetOffPartnerId { get => get_off_partner_id; set => get_off_partner_id = value; }
        public int ChangeStateRemainTime { get => change_state_remain_time; set => change_state_remain_time = value; }
        public MoveStateType TargetState { get => target_state; set => target_state = value; }
        //IReconnaissanceAttris
        private Dictionary<OprSubType, int> observe_distance;
        private List<int> see_enemy_bop_ids;
        public Dictionary<OprSubType, int> ObserveDistance { get => observe_distance; }

        public List<int> SeeEnemyBopIDs { get => see_enemy_bop_ids; set => see_enemy_bop_ids = value; }
        //IStateAttris
        private bool stack;
        private bool keep;
        private int keep_remain_time;
        private bool lose_control;
        private int alive_remain_time;
        public bool Stack { get => stack; set => stack = value; }
        public bool Keep { get => keep; set => keep = value; }
        public int KeepRemainTime { get => keep_remain_time; set => keep_remain_time = value; }
        public bool LoseControl { get => lose_control; set => lose_control = value; }
        public int AliveRemainTime { get => alive_remain_time; set => alive_remain_time = value; }

        //IAttackAttris
        private bool a1;
        private List<WeaponType> carry_weapon_ids = new List<WeaponType>();
        private Dictionary<BulletType, int> remain_bullet_nums = new Dictionary<BulletType, int>();
        private Dictionary<BulletType, int> remain_bullet_nums_bk = new Dictionary<BulletType, int>();
        private bool guide_ability;
        private int weapon_cool_time;
        private int weapon_unfold_time;
        private int weapon_unfold_state;
        public bool A1 { get => a1; }

        public List<WeaponType> CarryWeaponIDs { get => carry_weapon_ids; }

        public Dictionary<BulletType, int> RemainBulletNums { get => remain_bullet_nums; set => remain_bullet_nums = value; }
        public Dictionary<BulletType, int> RemainBulletNumsBK { get => remain_bullet_nums_bk; set => remain_bullet_nums_bk = value; }

        public bool GuideAbility { get => guide_ability; }

        public int WeaponCoolTime { get => weapon_cool_time; set => weapon_cool_time = value; }
        public int WeaponUnfoldTime { get => weapon_unfold_time; set => weapon_unfold_time = value; }
        public int WeaponUnfoldState { get => weapon_unfold_state; set => weapon_unfold_state = value; }

        public void SetUp(OperatorMsg operatorMsg)
        {
            //ICommonAttris
            obj_id = operatorMsg.obj_id;
            name = operatorMsg.name;
            color = (Color)operatorMsg.color;
            type = (OprType)operatorMsg.type;
            sub_type = (OprSubType)operatorMsg.sub_type;
            value = operatorMsg.value;
            blood = operatorMsg.blood;
            max_blood = operatorMsg.max_blood;
            //IMoveAttris
            basic_speed = operatorMsg.basic_speed;
            move_state = (MoveStateType)operatorMsg.move_state;
            cur_hex = operatorMsg.cur_hex;
            cur_pos = operatorMsg.cur_pos;
            speed = operatorMsg.speed;
            move_to_stop_remain_time = operatorMsg.move_to_stop_remain_time;
            can_to_move = operatorMsg.can_to_move;
            flag_force_stop = operatorMsg.flag_force_stop;
            stop = operatorMsg.stop;
            move_path = operatorMsg.move_path;
            tire = operatorMsg.tire;
            tire_accumulate_time = operatorMsg.tire_accumulate_time;
            on_board = operatorMsg.on_board;
            car = operatorMsg.car ?? -1;
            launcher = operatorMsg.launcher ?? -1;
            get_on_remain_time = operatorMsg.get_on_remain_time;
            get_on_partner_id = operatorMsg.get_on_partner_id;
            get_off_remain_time = operatorMsg.get_off_remain_time;
            get_off_partner_id = operatorMsg.get_off_partner_id;
            change_state_remain_time = operatorMsg.change_state_remain_time;
            target_state = (MoveStateType)operatorMsg.target_state;
            //IReconnaissanceAttris
            if (operatorMsg.observe_distance == null)
            {
                observe_distance = new Dictionary<OprSubType, int>
                {
                    {OprSubType.Tank, 2},
                    {OprSubType.IFV, 2},
                    {OprSubType.Infantry, 2},
                    {OprSubType.Artillery, 2},
                    {OprSubType.UGV, 2},
                    {OprSubType.Drone, 0},
                    {OprSubType.Helicopter, 0},
                    {OprSubType.CruisingMissile, 0},
                };
            }
            else
            {
                foreach (var od in operatorMsg.observe_distance)
                {
                    observe_distance.Add((OprSubType)od.Key, od.Value);
                }
            }
            see_enemy_bop_ids = operatorMsg.see_enemy_bop_ids ?? new List<int>();
            //IStateAttris
            stack = operatorMsg.stack;
            keep = operatorMsg.keep;
            keep_remain_time = operatorMsg.keep_remain_time;
            lose_control = operatorMsg.lose_control;
            alive_remain_time = operatorMsg.alive_remain_time;
        }
        public void UpdataStandaloneAttris(List<IJudgeResult> judge_results, Map map)
        {
            foreach (IJudgeResult judge_result in judge_results)
            {
                if (judge_result.ObjID != obj_id) continue;// 不是此算子执行的动作的裁决结果，跳过
                // 引导射击无论是否成功都要冷却
                if (judge_result.ActionType == ActionType.GuideShoot) UpdateGuideShootAttris(judge_result);// 引导射击裁决结果更新
                else
                {
                    if (!judge_result.IsSuccess) continue;  // 裁决没有执行成功，跳过

                    else if (judge_result.ActionType == ActionType.Move) UpdataMoveAttris(judge_result, map);// 机动裁决结果更新
                    else if (judge_result.ActionType == ActionType.StopMove) UpdataStopMoveAttris(judge_result);// 停止机动裁决结果更新
                }
            }
            PutForwardObservation(map);// 更新持续性动作，如机动和各种倒计时等
        }
        public void UpdateAssociatedAttris(List<IOperator> oprs, List<IOperator> passengers, Map map)
        {
            UpdataSeeEnemyAttris(oprs, map);// 更新观察敌方算子属性
        }
        public Dictionary<int, List<ActionMsg>> ConfirmValidActions(List<OperatorMsg> oprs, CityMsg[] cities, Map map, ShootJudgeTable shootJudgeTable, List<IOperator> passengers)
        {
            Dictionary<int, List<ActionMsg>> individualValidActions = new Dictionary<int, List<ActionMsg>>();

            // 判断算子是否能机动
            bool move_flag = true;  // 能够机动的标识
            List<ActionMsg> move_action = new List<ActionMsg>();// 新建机动动作
            if (speed > 0) move_flag = false;   //未停下的算子不可机动
            if (!can_to_move && move_to_stop_remain_time > 0) move_flag = false;// 如果在停止机动的惩罚中，不可以机动
            if (move_flag)// 如果可以机动
            {
                move_action.Add(new ActionMsg { type = (int)ActionType.Move, obj_id = obj_id });// 设置动作类型、算子id
                individualValidActions.Add((int)ActionType.Move, move_action);// 动作集合添加进合法动作以该动作类型为键的值中
            }

            // 判断能否停止机动
            if (speed > 0)// 正在机动
            {
                List<ActionMsg> stop_move_action = new List<ActionMsg>();// 新建停止机动动作
                stop_move_action.Add(new ActionMsg { type = (int)ActionType.StopMove, obj_id = obj_id });// 设置动作类型、算子id
                individualValidActions.Add((int)ActionType.StopMove, stop_move_action);// 动作集合添加进合法动作以该动作类型为键的值中
            }

            // 判断能否引导射击
            bool flagGuideShoot = true;// 可以引导射击的标志位
            List<ActionMsg> guide_shoot_action = new List<ActionMsg>();// 新建引导射击动作集合
            if (!guide_ability) flagGuideShoot= false;// 如果没有引导射击能力，不可以执行
            else if (!stop) flagGuideShoot = false;// 如果不处于静止状态，不可以执行
            else if (weapon_cool_time > 0) flagGuideShoot = false;// 如果引导射击75秒冷却中，不可以执行
            else if (see_enemy_bop_ids.Count > 0)// 如果有观察到的敌方
            {
                foreach (var opr in oprs)
                {
                    // 携带重型导弹
                    if (opr.color != (int)color || opr.carry_weapon_ids == null || opr.sub_type != (int)OprSubType.IFV)// 不是己方战车，或者没有携带武器
                    {
                        continue;// 跳过
                    }
                    if (opr.carry_weapon_ids.Contains((int)WeaponType.HeavyMissile))// 如果战车携带了重型导弹
                    {
                        if (opr.weapon_cool_time > 0 || opr.weapon_unfold_time > 0 || opr.weapon_unfold_state == 0 || opr.change_state_remain_time > 0
                            || opr.get_off_remain_time > 0 || opr.get_on_remain_time > 0 || !opr.stop) continue;// 如果战车武器在冷却，武器没展开，或者正在执行其他动作，跳过

                        foreach (var enemy in oprs)// 寻找可以攻击的敌方
                        {
                            if (see_enemy_bop_ids.Contains(enemy.obj_id))// 如果本算子可以看见
                            {
                                bool can_see = true;
                                int distance = map.GetDistance(opr.cur_hex, enemy.cur_hex);// 战车与敌方算子的距离
                                int attack_level = shootJudgeTable.CalcAttackLevel(can_see, opr.remain_bullet_nums, WeaponType.HeavyMissile, enemy.type, distance, opr.blood);
                                if (attack_level > 0)// 如果攻击等级大于0
                                {
                                    guide_shoot_action.Add(// 创建引导射击动作，并添加
                                        new ActionMsg
                                        {
                                            type = (int)ActionType.GuideShoot,// 动作类型
                                            obj_id = obj_id,// 算子id
                                            guided_obj_id = opr.obj_id,// 被引导的战车id
                                            target_obj_id = enemy.obj_id,// 射击目标id
                                            weapon_id = (int)WeaponType.HeavyMissile,// 武器id
                                            attack_level = attack_level// 攻击等级
                                        }
                                        );
                                }
                            }
                        }
                    }
                }
            }
            if (flagGuideShoot)// 如果可以引导射击
            {
                if (guide_shoot_action.Count > 0)// 如果有可以执行的引导射击动作
                {
                    individualValidActions.Add((int)ActionType.GuideShoot, guide_shoot_action);// 动作集合添加进合法动作以该动作类型为键的值中
                }
            }
            return individualValidActions;
        }
        private void PutForwardObservation(Map map)
        {
            // 修改机动属性
            if (speed > 0 && move_path.Count > 0)// 速度大于0，有机动路径
            {
                float percetage = (float)speed / 3.6f / (float)map.Width;// 计算一个step移动了多远（speed是km/h，除3.6得到m/s，除六角格宽度（单位为米））
                cur_pos += percetage;
                if (cur_pos >= 1)  // 到达了下一格
                {
                    cur_pos = 0;
                    cur_hex = move_path[0];// 修改位置
                    move_path.RemoveAt(0);// 修改机动路径
                    if (move_path.Count <= 0)  // 转为停止
                    {
                        speed = 0;
                        move_to_stop_remain_time = 76;// 机动转静止倒计时
                    }
                    else// 还有没走完的机动路径
                    {
                        speed = (int)(basic_speed / map.GetHexCosts(cur_hex / 100, cur_hex % 100, MoveMode.Fly)[move_path[0]]);// 计算速度（基础速度除通行代价）
                    }
                }
            }
            // 停止机动
            if (flag_force_stop)// 如果被停止机动
            {
                if (speed == 0)// 如果没有在机动
                {
                    if (can_to_move)// 如果可以机动（75秒停止机动倒计时结果）
                    {
                        flag_force_stop = false;// 停止机动的标志位设置为false
                    }
                }
                else if (cur_pos <= 0)// 如果正在机动，且完成了当前格机动
                {
                    if (move_path == null) move_path = new List<int>();// 清除机动路径
                    else move_path.Clear();
                    speed = 0;// 停止机动
                    move_to_stop_remain_time = 76;// 机动转停止倒计时
                    can_to_move = false;// 不可机动
                }
            }
            // 75秒倒计时
            if (move_to_stop_remain_time > 0)  // 停止倒计时
            {
                move_to_stop_remain_time--;
                if (move_to_stop_remain_time <= 0)// 如果倒计时结束
                {
                    can_to_move = true;// 可以继续机动
                    flag_force_stop = false;// 停止机动的标志位设置为false
                    stop = true;// 处于静止状态
                }
            }
            if (weapon_cool_time > 0)  // 引导射击冷却倒计时
            {
                weapon_cool_time--;
            }
        }
        private void UpdataMoveAttris(IJudgeResult judge_result, Map map)
        {
            if (judge_result.ActionType != ActionType.Move)
            {
                return;
            }

            MoveJudgeResult moveJudgeResult = (MoveJudgeResult)judge_result;// 强转为机动裁决结果类型
            //修改算子属性
            speed = (int)(basic_speed / map.GetHexCosts(cur_hex / 100, cur_hex % 100, MoveMode.Fly)[moveJudgeResult.MovePath[0]]);// 修改速度，基础速度除通行代价
            stop = false;// 静止标志位设置为false
            move_path = moveJudgeResult.MovePath;// 保存机动路径
            move_to_stop_remain_time = 0;// 结束机动转停止倒计时
        }
        private void UpdataStopMoveAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.StopMove)
            {
                return;
            }
            flag_force_stop = true;// 停止机动标志位设置为true
        }
        private void UpdateGuideShootAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.GuideShoot || judge_result.ObjID != obj_id)
            {
                return;
            }
            weapon_cool_time = 76;// 引导射击75秒倒计时
        }
        private void UpdataSeeEnemyAttris(List<IOperator> oprs, Map map)
        {
            if (observe_distance == null) return;// 如果观察距离属性没有数据，跳过

            if (see_enemy_bop_ids == null) see_enemy_bop_ids = new List<int>();// 清空，等待存入新的数据
            else see_enemy_bop_ids.Clear();
            for (int i = 0; i < oprs.Count; i++)// 遍历态势中的算子
            {
                if (!typeof(ICommonAttris).IsAssignableFrom(oprs[i].GetType()) ||
                    !typeof(IMoveAttris).IsAssignableFrom(oprs[i].GetType())) continue;

                Color enemy_color = (Color)oprs[i].GetType().GetProperty("Color").GetValue(oprs[i]);
                OprType enemy_type = (OprType)oprs[i].GetType().GetProperty("Type").GetValue(oprs[i]);
                int enemy_hex = (int)oprs[i].GetType().GetProperty("CurHex").GetValue(oprs[i]);
                OprSubType enemy_sub_type = (OprSubType)oprs[i].GetType().GetProperty("Subtype").GetValue(oprs[i]);
                MoveStateType enemy_move_state = (MoveStateType)oprs[i].GetType().GetProperty("MoveState").GetValue(oprs[i]);

                if (color == enemy_color) continue;// 如果是己方算子，跳过

                if (map.CanSeeTerrain(type, enemy_type, cur_hex, enemy_hex, enemy_sub_type, observe_distance, enemy_move_state))// 如果可以看见
                {
                    see_enemy_bop_ids.Add(oprs[i].ObjID);// 添加
                }
            }
        }
    }
}
